package stdio.costa.imoca.utils;

import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Position;
import stdio.costa.imoca.model.ImageInfo;
import stdio.costa.imoca.model.TextInfo;

public class ImageUtils {

	private static final String PICTRUE_FORMATE_JPG = "jpg";

	private static final Position RANDOM_POSITION = new RandomPosition();

	public static byte[] zoom(byte[] original, int width, int height)
			throws IOException {
		return zoom(new ByteArrayInputStream(original), width, height);
	}

	public static byte[] zoom(InputStream original, Integer width,
			Integer height) throws IOException {
		if (width == null || height == null || width <= 0 || height <= 0) {
			return IOUtils.read(original);
		}
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		Thumbnails.of(original).size(width, height).outputQuality(1.0f)
				.toOutputStream(output);
		return output.toByteArray();
	}

	public static byte[] addWatermarkRandomly(byte[] original, byte[] watermark)
			throws IOException {
		return addWatermarkRandomly(new ByteArrayInputStream(original),
				new ByteArrayInputStream(watermark));
	}

	public static byte[] addWatermarkRandomly(InputStream original,
			InputStream watermark) throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		BufferedImage image = ImageIO.read(original);
		BufferedImage watermarkImage = ImageIO.read(watermark);
		Thumbnails.of(image).size(image.getWidth(), image.getHeight())
				.watermark(RANDOM_POSITION, watermarkImage, 0.8f)
				.outputFormat("JPEG").toOutputStream(output);
		return output.toByteArray();
	}

	public static byte[] combineHorizontally(int width, int height,
			int horizontalMargin, int verticalMargin, byte[]... inputs)
			throws IOException {
		ByteArrayInputStream[] ins = IOUtils.asByteArrayInputStreams(inputs);
		return combineHorizontally(width, height, horizontalMargin,
				verticalMargin, ins);
	}

	public static byte[] combineHorizontally(int width, int height,
			int horizontalMargin, int verticalMargin, InputStream... inputs)
			throws IOException {
		BufferedImage result = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_ARGB);
		Graphics graphics = result.getGraphics();
		int x = 0, y = verticalMargin, perWidth = width / inputs.length - 2
				* horizontalMargin;
		for (InputStream in : inputs) {
			BufferedImage image = ImageIO.read(in);
			x = x + horizontalMargin;
			graphics.drawImage(image, x, y, perWidth, height, null);
			x = x + perWidth + horizontalMargin;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();

		ImageIO.write(result, "PNG", out);

		return out.toByteArray();
	}

	public static byte[] injectImageAndTextList(InputStream original,
			ImageInfo imageInfo, List<TextInfo> textInfoList)
			throws IOException {
		
		if (textInfoList == null || textInfoList.isEmpty() || imageInfo == null) {
			new IllegalArgumentException(
					"text info or image info could not be empty");
		}

		Image image = ImageIO.read(original);

		BufferedImage bufferedImage = new BufferedImage(image.getWidth(null),
				image.getHeight(null), BufferedImage.TYPE_INT_RGB);

		Graphics2D g = bufferedImage.createGraphics();

		g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null),
				null);
		
		injectImage(g, imageInfo);

		for (TextInfo textInfo : textInfoList) {
			injectText(g, textInfo);
		}

		g.dispose();

		ByteArrayOutputStream out = new ByteArrayOutputStream();

		ImageIO.write(bufferedImage, PICTRUE_FORMATE_JPG, out);

		return out.toByteArray();

	}

	private static void injectText(Graphics2D g, TextInfo textInfo)
			throws IOException {

		g.setFont(new Font(textInfo.getFontName(), textInfo.getFontStyle(),
				textInfo.getFontSize()));
		
		g.setColor(textInfo.getColor());
		
		g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
				textInfo.getAlpha()));
		
		g.drawString(textInfo.getPressText(), textInfo.getX(), textInfo.getY());

	}

	private static void injectImage(Graphics2D g,
			ImageInfo imageInfo) throws IOException {

		Image greetingkImg = ImageIO.read(imageInfo.getGreetingImgkStream());

		g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
				imageInfo.getAlpha()));

		g.drawImage(greetingkImg, imageInfo.getX(), imageInfo.getY(),
				imageInfo.getWidth(), imageInfo.getWidth(), null);
	}

	public final static byte[] injectImage(InputStream originalImgStream,
			InputStream greetingImgkStream, int x, int y, int width,
			int height, float alpha) throws IOException {

		Image originalImg = ImageIO.read(originalImgStream);

		BufferedImage image = new BufferedImage(originalImg.getWidth(null),
				originalImg.getHeight(null), BufferedImage.TYPE_INT_RGB);

		Graphics2D g = image.createGraphics();

		g.dispose();

		ByteArrayOutputStream out = new ByteArrayOutputStream();

		ImageIO.write(image, PICTRUE_FORMATE_JPG, out);

		return out.toByteArray();
	}

	public static byte[] combineVertically(int width, int height,
			int horizontalMargin, int verticalMargin, byte[]... inputs)
			throws IOException {
		ByteArrayInputStream[] ins = IOUtils.asByteArrayInputStreams(inputs);
		return combineVertically(width, height, horizontalMargin,
				verticalMargin, ins);
	}

	public static byte[] combineVertically(int width, int height,
			int horizontalMargin, int verticalMargin, InputStream... inputs)
			throws IOException {
		BufferedImage result = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_ARGB);
		Graphics graphics = result.getGraphics();
		int x = horizontalMargin, y = 0, perHeight = height / inputs.length - 2
				* verticalMargin;
		for (InputStream in : inputs) {
			BufferedImage image = ImageIO.read(in);
			y = y + verticalMargin;
			graphics.drawImage(image, x, y, width, perHeight, null);
			y = y + perHeight + verticalMargin;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();

		ImageIO.write(result, "PNG", out);

		return out.toByteArray();
	}

	private static class RandomPosition implements Position {

		@Override
		public Point calculate(int enclosingWidth, int enclosingHeight,
				int width, int height, int insetLeft, int insetRight,
				int insetTop, int insetBottom) {
			Random random = new Random();
			int x = random.nextInt(enclosingWidth - width);
			int y = random.nextInt(enclosingHeight - height);
			return new Point(x, y);
		}

	}
}